package controllers;

import org.hibernate.engine.Status;

import models.*;
import play.cache.Cache;
import play.data.validation.Required;
import play.db.jpa.Model;
import play.mvc.*;
import models.Tutorial.*;
import play.*;
import play.db.jpa.*;
import java.util.*;

import javax.management.Query;

public class Reviews extends Controller {

	/**
	 * This method takes the input review of the reviewer and saves it in the
	 * database after passing the parameters of the Review to the constructor in
	 * the Models
	 * 
	 * @param userId
	 *            , tutId , review
	 * @author Mahmoud
	 * 
	 * @author Omnia - new Notification
	 **/
	public static void addReviewToDatabase(long userId, long tutId,
			@Required(message = "Please enter a Review!") String review) {

		if (session.get("RegisteredUserId") != null) {
			if (validation.hasErrors()) {
				params.flash();
				validation.keep();
				addReviewPage(userId, tutId);
			} else {
				long uId = Long.parseLong(session.get("RegisteredUserId"));
				models.RegisteredUser user = models.RegisteredUser
						.findById(uId);
				models.Tutorial t = models.Tutorial.findById(tutId);
				List<Review> revs = models.Review.find(
						"tutId =? and userId =?", tutId, uId).fetch();
				if (t.creator != user || !(t.contributorsList.contains(user))) {
					if (revs.size() == 0) {
						models.Review rev = new models.Review(uId, tutId,
								review).save();
						new Notification(rev.getUserId(), t.creator.id, rev.id,
								11).save();
						promptSent();
					} else {
						youReviewedBefore();

					}
				} else {
					youAreCreatorOrContributor();
				}
			}
		} else
			notLoggedIn();
	}

	/**
	 * Method to view notLoggedIn.html which prompts the user that he/she is not
	 * logged in
	 * 
	 * @author Mahmoud
	 */
	public static void notLoggedIn() {
		render();
	}

	/**
	 * Method to view promptSent.html which prompts the user that his/her review
	 * has been sent
	 * 
	 * @author Mahmoud
	 */
	public static void promptSent() {
		render();
	}

	public static void openTutorial() {
		render();
	}

	/**
	 * This method displays to reviewer the file named addReview.html which
	 * takes the input review of the user in a text box while taking the
	 * tutorial Id from the tutorialPage.html
	 * 
	 * @author Mahmoud
	 * @param uId
	 *            which is the user Id
	 * @param id
	 *            which is the tutorial id coming from the URL when pressed on
	 *            the review button
	 **/

	public static void addReviewPage(long uId, long id) {
		if (session.get("RegisteredUserId") != null) {
			long useId = Long.parseLong(session.get("RegisteredUserId"));
			models.RegisteredUser user = models.RegisteredUser.findById(useId);
			models.Tutorial t = models.Tutorial.findById(id);
			List<Review> revs = models.Review.find("tutId =? and userId =?",
					id, useId).fetch();
			List<Review> reviewz = models.Review.find("tutId =?", id).fetch();
			if (t.creator != user || !(t.contributorsList.contains(user))) {
				if (user.getReviewer()) {
					if (revs.size() == 0) {
						if (reviewz.size() == 0) {
							render(useId, id);
						} else {
							reviewedTutorial();
						}
					} else {
						youReviewedBefore();
					}

				} else {
					notReviewer();
				}

			} else
				youAreCreatorOrContributor();
		} else
			notLoggedIn();
	}

	/**
	 * Method to view reviewedTutorial.html which prompts the user that this
	 * tutorial is already reviewed or under review process
	 * 
	 * @author Mahmoud
	 */
	public static void reviewedTutorial() {
		render();
	}

	/**
	 * Method to view notReviewer.html which prompts the user that he/she is not
	 * a reviewer
	 * 
	 * @author Mahmoud
	 */
	public static void notReviewer() {
		render();
	}

	/**
	 * Method to view youAreCreatorOrContributor.html which prompts the user
	 * that he/she is the creator of the tutorial
	 * 
	 * @author Mahmoud
	 */
	public static void youAreCreatorOrContributor() {
		render();
	}

	/**
	 * Method to view youReviewedBefore.html which prompts the user that he/she
	 * has reviewed this tutorial before
	 * 
	 * @author Mahmoud
	 */
	public static void youReviewedBefore() {
		render();
	}

	/**
	 * this method will get all the replies made on a reply the users that are
	 * able to view it are the reviewer that made the review, the creator and
	 * the contributor of the tutorial
	 * 
	 * @param reviewId
	 * @author Ghada Kades
	 * 
	 */
	public static List<Reply> viewReplies(long reviewId) {

		Review currentReview = Review.findById(reviewId);
		List<Reply> replies = new ArrayList<Reply>();

		if (currentReview.isReplied == true) {
			replies = Reply.find("reviewID = ?", reviewId).fetch();
			List<RegisteredUser> repliers = new ArrayList<RegisteredUser>();
			for (int i = 0; i < replies.size(); i++) {
				RegisteredUser ru = RegisteredUser
						.findById(replies.get(i).userId);
				repliers.add(i, ru);
			}
			return (replies);
		}
		return replies;
	}

	/**
	 * this method will get all the reviews made on a tutorial the users that
	 * are able to view it are the reviewer that made the review, the creator
	 * and the contributor of the tutorial and tutorial should be publish
	 * 
	 * @param tutId
	 * @author shayma hesham
	 * 
	 */

	/**
	 * I called my method and added a list of repliers to be able to view all
	 * the replies with the review in the same page
	 * 
	 * @author Ghada Kades
	 */
	public static void viewReview(long tutId) {
		try {
			long userId = Long.parseLong(session.get("RegisteredUserId"));
			RegisteredUser user = RegisteredUser.findById(userId);

			Tutorial tutorial = Tutorial.findById(tutId);

			Review rev = null;

			if (((tutorial.contributorsList.contains(user)) || user.isReviewer || user.id == tutorial.creator.id)
					&& tutorial.status == "draft") {

				List<Review> r = Review.find("tutId=? ", tutId).fetch();
				rev = new Review();

				for (int i = 0; i < r.size(); i++) {
					if (r.get(i).getTutId() == tutId) {
						rev = r.get(i);
					}
				}
				long id = rev.getId();

				List<Reply> replies = viewReplies(id);
				List<RegisteredUser> repliers = new ArrayList<RegisteredUser>();
				for (int i = 0; i < replies.size(); i++) {
					RegisteredUser ru = RegisteredUser
							.findById(replies.get(i).userId);
					repliers.add(i, ru);
				}

				render(rev, replies, repliers);

			} else {
				String str = "The user is not contributor.";
				render(str);

			}
		} catch (Exception e) {
			noReview();
		}
	}

	/**
	 * Method to view noReview.html which tell the user that there are no
	 * reviews
	 * 
	 * @author shayma hesham
	 */

	public static void noReview() {
		render();
	}

	/**
	 * This method saves the reply of the creator/contributor or reviewer of the
	 * tutorial on the review msade by the reviewer
	 * 
	 * @author Dina
	 * @param reply
	 *            , reviewId
	 **/
	public static void replyReview(
			@Required(message = "Please Enter Your Reply") String reply,
			long reviewId) {
		try {

			long userId = Long.parseLong(session.get("RegisteredUserId"));
			RegisteredUser user = RegisteredUser.findById(userId);
			Review review = Review.findById(reviewId);

			if ((session.get("RegisteredUserId") != null)
					|| (Review.findById(reviewId) != null)
					|| review.getTutId() != 0) {
				models.Tutorial tutorial = models.Tutorial.findById(review
						.getTutId());
				RegisteredUser creator = tutorial.creator;
				RegisteredUser reviewer = RegisteredUser.findById(review
						.getUserId());
				if (validation.hasErrors()) {
					params.flash();
					validation.keep();
					viewReview(tutorial.id);
				} else {
					if (userId == creator.id
							|| (tutorial.contributorsList.contains(user))) {
						Reply userReply = new Reply(reply, review.id,
								creator.id);
						userReply.setRevieweReplies(review);
						userReply.save();
						review.setReplied(true);
						review.save();
						Notification creatorNotification = new Notification(
								userId, reviewer.getId(), reviewId, 12);
						creatorNotification.save();
						viewReview(tutorial.id);
					} else {
						if (userId == reviewer.id) {
							models.Reply userReply = new models.Reply(reply,
									review.id, reviewer.getId());
							userReply.setRevieweReplies(review);
							userReply.save();
							review.setReplied(true);
							review.save();
							Notification reviewerNotification = new Notification(
									reviewer.id, creator.getId(), reviewId, 12);
							reviewerNotification.save();
							Notification contributorNotification;
							for (int i = 0; i < tutorial.contributorsList
									.size(); i++) {
								contributorNotification = new Notification(
										reviewer.id,
										tutorial.contributorsList.get(i).id,
										reviewId, 12);
								contributorNotification.save();
							}
							viewReview(tutorial.id);

						} else {
							error();
						}
					}
				}
			} else {
				alreadyDeleted();
			}
		} catch (Exception e) {
			error();
		}

	}

	/**
	 * This method saves in the DB that the creator/contributor accepted the
	 * review or in case of the reviewer it saves that he accepted the advises
	 * of the creator/contributor on the review and enable the creator to
	 * publish the tutorial.
	 * 
	 * @author Dina
	 * @param reviewId
	 **/
	public static void acceptReview(long reviewId) {
		try {
			long userId = Long.parseLong(session.get("RegisteredUserId"));
			RegisteredUser user = RegisteredUser.findById(userId);
			Review review = Review.findById(reviewId);
			Tutorial tutorial = Tutorial.findById(review.getTutId());
			RegisteredUser creator = tutorial.creator;
			RegisteredUser reviewer = RegisteredUser.findById(review
					.getUserId());

			if ((!(review.isCreatorAccept()))
					&& (userId == creator.id || (tutorial.contributorsList
							.contains(user)))) {

				Notification notification = new Notification(userId,
						reviewer.getId(), reviewId, 13);
				notification.save();
				review.setCreatorAccept(true);
				review.save();
				accept();

			} else {
				if ((user.id == reviewer.id) && (!(review.isReadyToPublish()))) {
					Notification notification = new Notification(
							reviewer.getId(), creator.getId(), reviewId, 13);
					notification.save();
					Notification contributorNotification;
					for (int i = 0; i < tutorial.contributorsList.size(); i++) {
						contributorNotification = new Notification(reviewer.id,
								tutorial.contributorsList.get(i).id, reviewId,
								12);
						contributorNotification.save();
					}
					review.setReadyToPublish(true);
					review.save();
					accept();
				} else {
					alreadyAccepted();
				}
			}
		} catch (Exception e) {
			error();
		}
	}

	/**
	 * This method delete the review from the DB
	 * 
	 * @author Dina
	 * @param reviewId
	 **/
	public static void rejectReview(long reviewId) {
		try {
			long userId = Long.parseLong(session.get("RegisteredUserId"));
			RegisteredUser user = RegisteredUser.findById(userId);

			if ((session.get("RegisteredUserId") != null)
					|| (Review.findById(reviewId) != null)) {
				Review review = Review.findById(reviewId);
				Tutorial tutorial = Tutorial.findById(review.getTutId());
				RegisteredUser creator = tutorial.creator;

				if (userId == creator.id
						|| (tutorial.contributorsList.contains(user))) {
					Notification notification = new Notification(userId,
							review.getUserId(), reviewId, 14);
					notification.save();
					review.delete();
					LogRecord.createLog("Delete the review :", user);

					deleted();
				} else {
					alreadyDeleted();
				}
			} else {
				alreadyDeleted();
			}
		} catch (Exception e) {
			alreadyDeleted();
		}
	}

	/**
	 * This method renders to accept.html
	 * 
	 * @author Dina
	 * */
	public static void accept() {
		render();
	}

	/**
	 * This method renders to alreadyDeleted.html
	 * 
	 * @author Dina
	 * */
	public static void alreadyDeleted() {
		render();
	}

	/**
	 * This method renders to error.html
	 * 
	 * @author Dina
	 * */
	public static void error() {
		render();
	}

	/**
	 * This method renders to deleted.html
	 * 
	 * @author Dina
	 * */
	public static void deleted() {
		render();
	}

	public static void alreadyAccepted() {
		render();
	}

}
